﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using TSharp.Core.Util.Config;

namespace TSharp.Core.Util.Config
{
    /// <summary>
    /// 序列化器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Formatter<T>
    {
        private static readonly Type ObjType = typeof(T);
        private readonly IFormatter _formatter;
        private readonly XmlSerializer _serializer;

        #region ctor

        /*
        public Formatter()
            : this(FormatType.Xml)
        {
        }
*/
        private readonly FormatType _ftype = FormatType.Xml;

        /// <summary>
        /// 格式化器构造
        /// </summary>
        /// <param name="type"></param>
        public Formatter(FormatType type)
        {
            _ftype = type;
            switch (type)
            {
                case FormatType.Binary:
                    _formatter = new BinaryFormatter();
                    break;
                case FormatType.SoapXml:
                    _formatter = new SoapFormatter();
                    break;
                case FormatType.Xml:
                    _serializer = new XmlSerializer(ObjType);
                    break;
                default:
                    throw new ArgumentException("不支持的格式化类型！");
            }
        }

        #endregion

        #region 从字节流中序列化、反序列化对象

        /// <summary>
        /// 
        /// <para>by tangjingbo at 2010/6/25 23:11</para>
        /// </summary>
        /// <param name="serializationStream">The serialization stream.</param>
        /// <returns></returns>
        public T Deserialize(Stream serializationStream)
        {
            if (_serializer != null)
                return (T)_serializer.Deserialize(serializationStream);
            else
                return (T)_formatter.Deserialize(serializationStream);
        }

        /// <summary>
        /// Serializes the specified serialization stream.
        /// </summary>
        /// <param name="serializationStream">The serialization stream.</param>
        /// <param name="graph">The graph.</param>
        public void Serialize(Stream serializationStream, T graph)
        {
            if (_serializer != null)
                _serializer.Serialize(serializationStream, graph);
            else
                _formatter.Serialize(serializationStream, graph);
        }

        #endregion

        #region 从字符串中序列化、反序列化对象

        private readonly Encoding _encoding = Encoding.UTF8;

        /// <summary>
        /// 从字符串中反序列化对象
        /// <para>by tangjingbo at 2009/12/25 22:08</para>
        /// </summary>
        /// <param name="serializeString">序列化后的字符串.</param>
        /// <returns></returns>
        public T Deserialize(string serializeString)
        {
            if (_ftype == FormatType.Xml)
            {
                using (Stream stream = new MemoryStream())
                {
                    using (var sw = new StreamWriter(stream, Encoding.Unicode))
                    {
                        sw.Write(serializeString);
                        sw.Flush();
                        stream.Flush();
                        stream.Position = 0;
                    }
                    return Deserialize(stream);
                }
            }
            else if (_ftype == FormatType.SoapXml)
            {
                using (Stream stream = new MemoryStream())
                {
                    //soap 時
                    using (var sw = new StreamWriter(stream, _encoding))
                    {
                        sw.Write(serializeString);
                        sw.Flush();
                        stream.Flush();
                        stream.Position = 0;
                        return Deserialize(stream);
                    }
                }
            }
            else if (_ftype == FormatType.Binary)
            {
                using (Stream stream = GetStringStream(serializeString))
                {
                    stream.Flush();
                    stream.Position = 0;
                    return Deserialize(stream);
                }
            }
            throw new NotSupportedException("");
        }

        /// <summary>
        /// 将对象序列化字符串
        /// <para>by tangjingbo at 2009/12/25 22:09</para>
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <returns>流化后的结果</returns>
        public string Serialize(T graph)
        {
            if (graph == null)
                throw new ArgumentNullException("graph");
            if (_ftype == FormatType.Xml)
            {
                var sb = new StringBuilder();
                using (XmlWriter xmlwriter = XmlWriter.Create(sb))
                {
                    if (xmlwriter != null) _serializer.Serialize(xmlwriter, graph);
                }
                return sb.ToString();
            }
            else if (_ftype == FormatType.SoapXml)
            {
                using (var stream = new MemoryStream())
                {
                    Serialize(stream, graph);
                    stream.Flush();
                    stream.Position = 0;
                    using (var sr = new StreamReader(stream, _encoding))
                        return sr.ReadToEnd();
                }
            }
            else if (_ftype == FormatType.Binary)
            {
                using (var stream = new MemoryStream())
                {
                    Serialize(stream, graph);
                    return GetStreamString(stream, _encoding);
                }
            }
            throw new NotSupportedException("");
        }

        #region

        private static string GetStreamString(Stream ms, Encoding encoding)
        {
            return Convert.ToBase64String(GetBytes(ms, encoding));
        }

        private static byte[] GetBytes(Stream ms, Encoding encoding)
        {
            ms.Flush();
            ms.Position = 0;
            using (var br = new BinaryReader(ms, encoding))
            {
                byte[] cache = br.ReadBytes((int)ms.Length);
                return cache;
            }
        }

        private static byte[] GetStringBytes(string base64Str)
        {
            return Convert.FromBase64String(base64Str);
        }

        private static MemoryStream GetStringStream(string base64Str)
        {
            var b = new MemoryStream(GetStringBytes(base64Str));
            return b;
        }

        #endregion

        #endregion

        #region 从文件中序列化、反序列化对象

        /// <summary>
        /// 从字符串中反序列化对象
        /// <para>by tangjingbo at 2009/12/25 22:08</para>
        /// </summary>
        /// <param name="fileFullPath">The file full path.</param>
        /// <returns></returns>
        public T DeserializeFromFile(string fileFullPath)
        {
            using (var fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                return Deserialize(fs);
            }
        }

        /// <summary>
        /// 将对象序列化字符串
        /// <para>by tangjingbo at 2009/12/25 22:09</para>
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="fileFullPath">The file full path.</param>
        public void SerializeToFile(T graph, string fileFullPath)
        {
            if (graph == null)
                throw new ArgumentNullException("graph");
            using (var fs = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write, FileShare.Read))
            {
                Serialize(fs, graph);
            }
        }

        #endregion
    }
}